package com.zbiti.anvil.basic.admin.gateway.common.aspect;

import com.zbiti.framework.mda.core.aop.IMdaDataScopeAspectFilter;
import com.zbiti.module.system.base.api.domain.SysCompanyDomain;
import com.zbiti.module.system.base.api.domain.SysDeptDomain;
import com.zbiti.module.system.base.api.domain.SysUserDomain;
import com.zbiti.module.system.base.api.service.ISysCompanyService;
import com.zbiti.module.system.base.api.service.ISysDeptService;
import com.zbiti.module.system.base.service.mapper.SysCompanyMapper;
import com.zbiti.module.system.base.service.mapper.SysDeptMapper;
import com.zbiti.module.uni.mda.api.domain.MdaAuthInfoDomain;
import com.zbiti.module.uni.mda.api.service.IMdaAuthInfoService;
import com.zbiti.sdk.common.enums.DataScopeEnum;
import com.zbiti.sdk.common.utils.AnvilStringUtils;
import com.zbiti.sdk.common.utils.CollectionUtils;
import com.zbiti.sdk.common.utils.SessionProxyUtils;
import com.zbiti.sdk.common.utils.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static com.zbiti.sdk.common.annotation.DataScope.NO_SCOPE_SQL;

/**
 * @author zy
 * @date 2024/12/27 9:26
 */
@Component
public class MdaDataScopeAspectFilter implements IMdaDataScopeAspectFilter {

    /**
     * 日志记录器
     */
    private final Logger logger = LoggerFactory.getLogger(MdaDataScopeAspectFilter.class);

    @Autowired(required = false)
    private IMdaAuthInfoService iMdaAuthInfoService;

    @Autowired
    private SysCompanyMapper sysCompanyMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    /**
     * 执行过滤
     *
     * @param joinPoint  切入点
     * @param modelName 表名
     * @return 过滤SQL字符串
     */
    @Override
    public String doFilter(JoinPoint joinPoint, String modelName) {
        // 权限限制SQL类别
        List<String> scopeSqls = new ArrayList<>();
        // 获取当前的用户
        SysUserDomain currentUser = SessionProxyUtils.getUserInfo(SysUserDomain.class);
        if (currentUser != null) {
            // 如果是超级管理员，则不过滤数据
            if (!currentUser.isAdmin()) {
                List<MdaAuthInfoDomain> mdaAuthInfoDomainList = iMdaAuthInfoService.getMdaAuthInfoListByUserId(modelName, currentUser.getUserId());
                List<MdaAuthInfoDomain> union = DataScopeEnum.union(mdaAuthInfoDomainList, mdaAuthInfoDomain -> DataScopeEnum.parse(mdaAuthInfoDomain.getDataScope()).get());
                if (CollectionUtils.isNotEmpty(union)) {
                    for (MdaAuthInfoDomain mdaAuthInfoDomain : union) {
                        Optional<DataScopeEnum> parse = DataScopeEnum.parse(mdaAuthInfoDomain.getDataScope());
                        if (parse.isPresent()) {
                            // 存在一个包含全部数据权限的角色则清空过滤脚本
                            if (DataScopeEnum.ALL == parse.get()) {
                                scopeSqls.clear();
                                break;
                            }
                            // 添加特殊权限过滤
                            this.addScopeSql(parse.get(), scopeSqls, mdaAuthInfoDomain, currentUser);
                        }else {
                            // 没有权限则不给任何数据
                            scopeSqls.add(NO_SCOPE_SQL);
                        }
                    }
                }else {
                    scopeSqls.add(NO_SCOPE_SQL);
                }
            }
        }else{
            scopeSqls.add(NO_SCOPE_SQL);
        }
        String sqls = String.join(" OR ", scopeSqls);
        logger.trace("dataScope={}", sqls);
        return sqls;
    }

    /**
     * 添加特殊权限过滤
     * @param scope
     * @param scopeSqls
     * @param mdaAuthInfoDomain
     * @param currentUser
     */
    private void addScopeSql(DataScopeEnum scope, List<String> scopeSqls, MdaAuthInfoDomain mdaAuthInfoDomain, SysUserDomain currentUser) {
        switch (scope) {
            case CUSTOM_COMPANY:
                scopeSqls.add(String.format(
                        "(%s.%s IN ( SELECT company_id FROM mda_auth_data_scope WHERE auth_id = %s ) )",
                        mdaAuthInfoDomain.getTableName(),
                        AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                        mdaAuthInfoDomain.getAuthId()));
                break;
            case CUSTOM_DEPT:
                scopeSqls.add(String.format(
                        "(%s.%s IN ( SELECT dept_id FROM mda_auth_data_scope WHERE auth_id = %s ) )",
                        mdaAuthInfoDomain.getTableName(),
                        AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                        mdaAuthInfoDomain.getAuthId()));
                break;
            case SELF_COMPANY:
                scopeSqls.add(String.format("(%s.%s = %s)",
                        mdaAuthInfoDomain.getTableName(),
                        AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                        currentUser.getCompanyId()));
                break;
            case SELF_COMPANY_AND_CHILD:
                // 公司级联树
                if (currentUser.getCompany() != null && currentUser.getCompanyId() != null) {
                    String ancestors = currentUser.getCompany().getAncestors();
                    if (StringUtils.isNotEmpty(ancestors)) {
                        // 当前公司和下级公司
                        scopeSqls.add(String.format(
                                "(%s.%s = %s OR %s.%s IN ( SELECT company_id FROM sys_company WHERE ancestors LIKE '%s,%s%%'))",
                                mdaAuthInfoDomain.getTableName(),
                                AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                                currentUser.getCompanyId(),
                                mdaAuthInfoDomain.getTableName(),
                                AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                                ancestors,
                                currentUser.getCompanyId()));
                    } else {
                        // 当前公司
                        scopeSqls.add(String.format("(%s.%s = %s)",
                                mdaAuthInfoDomain.getTableName(),
                                AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                                currentUser.getCompanyId()));
                    }
                } else {
                    scopeSqls.add(NO_SCOPE_SQL);
                }
                break;
            case SELF_DEPT:
                scopeSqls.add(String.format("(%s.%s = %s)",
                        mdaAuthInfoDomain.getTableName(),
                        AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                        currentUser.getDeptId()));
                break;
            case SELF_DEPT_AND_CHILD:
                // 部门级联树
                if (currentUser.getDept() != null && currentUser.getDeptId() != null) {
                    String ancestors = currentUser.getDept().getAncestors();
                    if (AnvilStringUtils.isNotEmpty(ancestors)) {
                        // 当前部门和下级部门
                        scopeSqls.add(String.format(
                                "(%s.%s = %s OR %s.%s IN ( SELECT dept_id FROM sys_dept WHERE ancestors LIKE '%s,%s%%'))",
                                mdaAuthInfoDomain.getTableName(),
                                AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                                currentUser.getDeptId(),
                                mdaAuthInfoDomain.getTableName(),
                                AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                                ancestors,
                                currentUser.getDeptId()));
                    } else {
                        // 当前部门
                        scopeSqls.add(String.format("(%s.%s = %s)",
                                mdaAuthInfoDomain.getTableName(),
                                AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                                currentUser.getDeptId()));
                    }
                } else {
                    scopeSqls.add(NO_SCOPE_SQL);
                }
                break;
            case SELF_USER:
                scopeSqls.add(String.format("(%s.%s = %s)",
                        mdaAuthInfoDomain.getTableName(),
                        AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "user_id" : mdaAuthInfoDomain.getFieldAlias(),
                        currentUser.getUserId()));
                break;
            case PARENT_COMPANY:
                if (currentUser.getCompany() != null && currentUser.getCompany().getParentId() != null) {
                    scopeSqls.add(String.format("(%s.%s = %s)",
                            mdaAuthInfoDomain.getTableName(),
                            AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                            currentUser.getCompany().getParentId()));
                } else {
                    scopeSqls.add(NO_SCOPE_SQL);
                }
                break;
            case PARENT_COMPANY_AND_CHILD:
                // 上级公司级联树
                if (currentUser.getCompany() != null && currentUser.getCompany().getParentId() != null) {
                    SysCompanyDomain parentCompany = sysCompanyMapper.selectById(currentUser.getCompany().getParentId());
                    if (parentCompany != null && parentCompany.getCompanyId() != null) {
                        String ancestors = parentCompany.getAncestors();
                        if (AnvilStringUtils.isNotEmpty(ancestors)) {
                            // 当前公司和下级公司
                            scopeSqls.add(String.format(
                                    "(%s.%s = %s OR %s.%s IN ( SELECT company_id FROM sys_company WHERE ancestors LIKE '%s,%s%%'))",
                                    mdaAuthInfoDomain.getTableName(),
                                    AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                                    parentCompany.getCompanyId(),
                                    mdaAuthInfoDomain.getTableName(),
                                    AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                                    ancestors,
                                    parentCompany.getCompanyId()));
                        } else {
                            // 当前公司
                            scopeSqls.add(String.format("(%s.%s = %s)",
                                    mdaAuthInfoDomain.getTableName(),
                                    AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "company_id" : mdaAuthInfoDomain.getFieldAlias(),
                                    parentCompany.getCompanyId()));
                        }
                    } else {
                        scopeSqls.add(NO_SCOPE_SQL);
                    }
                } else {
                    scopeSqls.add(NO_SCOPE_SQL);
                }
                break;
            case PARENT_DEPT:
                if (currentUser.getDept() != null && currentUser.getDept().getParentId() != null) {
                    scopeSqls.add(String.format("(%s.%s = %s)",
                            mdaAuthInfoDomain.getTableName(),
                            AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                            currentUser.getDept().getParentId()));
                } else {
                    scopeSqls.add(NO_SCOPE_SQL);
                }
                break;
            case PARENT_DEPT_AND_CHILD:
                if (currentUser.getDept() != null && currentUser.getDept().getParentId() != null) {
                    SysDeptDomain parentDept = sysDeptMapper.selectById(currentUser.getDept().getParentId());
                    if (parentDept != null && parentDept.getDeptId() != null) {
                        String ancestors = parentDept.getAncestors();
                        if (AnvilStringUtils.isNotEmpty(ancestors)) {
                            // 上级部门和下级部门
                            scopeSqls.add(String.format(
                                    "(%s.%s = %s OR %s.%s IN ( SELECT dept_id FROM sys_dept WHERE ancestors LIKE '%s,%s%%'))",
                                    mdaAuthInfoDomain.getTableName(),
                                    AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                                    parentDept.getDeptId(),
                                    mdaAuthInfoDomain.getTableName(),
                                    AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                                    ancestors,
                                    parentDept.getDeptId()));
                        } else {
                            // 上级部门
                            scopeSqls.add(String.format("(%s.%s = %s)",
                                    mdaAuthInfoDomain.getTableName(),
                                    AnvilStringUtils.isEmpty(mdaAuthInfoDomain.getFieldAlias()) ? "dept_id" : mdaAuthInfoDomain.getFieldAlias(),
                                    parentDept.getDeptId()));
                        }
                    } else {
                        scopeSqls.add(NO_SCOPE_SQL);
                    }
                } else {
                    scopeSqls.add(NO_SCOPE_SQL);
                }
                break;
            default:
                break;
        }
    }
}
